package it.ap.sa.acqua.auth.security;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import it.ap.sa.acqua.auth.service.UserService;
import it.ap.sa.acqua.auth.service.beans.CustomAuthenticationUserDetails;
import it.ap.sa.acqua.dao.model.TUser;
import it.ap.sa.acqua.dao.model.TUserProfile;
 
 
@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService{
 
    static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
     
    @Autowired
    private UserService userService;
     
    @Transactional(readOnly=true)
    public CustomAuthenticationUserDetails loadUserByUsername(String ssoId) throws UsernameNotFoundException {
    	CustomAuthenticationUserDetails userDTO = null;
    	
    	try{
	        TUser user = userService.findBySSO(ssoId);
	        logger.info("User : {}", user);
	        if(user ==null){
	            logger.info("User not found");
	            throw new UsernameNotFoundException("Username not found");
	        }
	        userDTO = new CustomAuthenticationUserDetails(user.getSsoId(), user.getPassword(), true, true, true, true, getGrantedAuthorities(user));
	        // set custom property
			userDTO.setUserId(String.valueOf(user.getId()));
			userDTO.setFirstname(user.getFirstName());
			userDTO.setLastname(user.getLastName());
			userDTO.setEmail(user.getEmail());
			userDTO.setUrlImage(user.getUrlImage());
			userDTO.setRole( (user.getTUserProfile()).getType() );
			userDTO.setDateBirth( user.getDateBirth() );
			
			return userDTO;
    	}catch(Exception e ){
			logger.error("loadUserByUsername >>> " + e, e);
			return userDTO;
		}
    }
    
    /**
	 * Restituisce l'anagrafica dell'utente autenticato dal token, altrimenti viene restituito il valore null
	 * 
	 * @return {@link CustomAuthenticationUserDetails}
	 */
	public CustomAuthenticationUserDetails getPrincipal() {
		try{
	    	/**
			 * Recupero i dati dell'utente autenticato 
			 */
			Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
			
			if(authentication != null && authentication.isAuthenticated() && authentication.getPrincipal() instanceof UserDetails)
			   return ((CustomAuthenticationUserDetails) authentication.getPrincipal());
			else
			   return null;
		}catch(Exception e){
			logger.error("getPrincipal >>>>>>>>>> " + e, e);
			throw(e);
		}
    }
     
    private List<GrantedAuthority> getGrantedAuthorities(TUser user){
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
         
        TUserProfile userProfile = user.getTUserProfile();
        logger.info("UserProfile : {}", userProfile);
        authorities.add(new SimpleGrantedAuthority("ROLE_"+userProfile.getType()));
        
        logger.info("authorities : {}", authorities);
        return authorities;
    }
    
    /**
	 * Ogetto user autenticazione di test.
	 * 
	 * @return {@link CustomAuthenticationUserDetails}
	 */
	public UserDetails loadUserByUsernameTest() throws UsernameNotFoundException {
		UserDetails userDTO = null;
		try{
			/** per spring */
			Collection<GrantedAuthority> authoritiesDTO = new ArrayList<GrantedAuthority>();
			
			/** lista codici ruoli (Stringhe prive del prefisso spring "ROLE_" */
			List<String> codeAuthorities = new ArrayList<String>();
			
			logger.info("Elenco ruoli: ");
				
			logger.info("ROLE_USER");
			/**
			 * Quindi creiamo un oggetto di SimpleGrantedAuthority perchè abbia il ruolo user.
			 */
			authoritiesDTO.add(new SimpleGrantedAuthority("ROLE_USER"));
			authoritiesDTO.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

			/**
			 * Aggiungo alla lista il codice del ruolo.
			 */
			codeAuthorities.add("USER");
			codeAuthorities.add("ADMIN");
			
			/**
			 * Dopo valorizziamo l' oggetto user personalizzato che avrà il nome utente, le credenziali, ed 
			 * eventuali altri campi come e-mail ecc.
			 */
			userDTO = new org.springframework.security.core.userdetails.User("test", "test", true, true, true, true, authoritiesDTO);
			// set custom property
//			userDTO.setUserId("9");
//			userDTO.setFirstname("John");
//			userDTO.setLastname("Doe");
//			userDTO.setEmail("john.doe@email.it");
//			userDTO.setAvatar("/app/shared/avatar/avatar2.png");
//			userDTO.setRoles(codeAuthorities);
			
			return userDTO;
		}catch(Exception e ){
			logger.error("loadUserByUsernameTest >>> " + e, e);
			return userDTO;
		}
	}
     
}